package com.rz.htk.order.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.rz.htk.order.entity.Commodity;
import com.rz.htk.order.entity.Order;
import com.rz.htk.order.entity.OrderTrack;
import com.rz.htk.order.entity.vo.SsEsId;
import com.rz.htk.order.service.CommodityService;
import com.rz.htk.order.service.IOrderTrackService;
import com.rz.htk.order.service.IOrderService;
import com.rz.htk.order.task.util.SecurityUtil;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.model.HttpRequestBody;
import us.codecraft.webmagic.utils.HttpConstant;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Service
@org.springframework.core.annotation.Order(1)
public class OrderTask {
    private Logger log = LoggerFactory.getLogger("OrderTask");

    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final String pushUrl = "http://api.kerrytj.com/ked/api/RequestShipment.ashx";
    private static final String customNo = "11249018";
    private static final String ysTrackUrl = "http://service.ycs-express.com/QueryYcsLongingjson.aspx?";
    private static final String pgsTrackUrl ="https://api.tw568.com/v1/customer/core_waybills/search";
    @Value("${orderPushApiKey}")
    private String apiKey;
    @Value("${yousu.track.push-url}")
    private String pushTrackToYouSuUrl;
    @Value("${yousu.track.api-key}")
    private String trackApiKey;
    @Value("${yousu.track.account}")
    private String account;


    @Autowired
    public OrderTask (OkHttpClient okHttpClient, CommodityService commodityService, IOrderService IOrderService, IOrderTrackService orderTrackService){
        this.okHttpClient = okHttpClient;
        this.commodityService = commodityService;
        this.IOrderService = IOrderService;
        this.orderTrackService = orderTrackService;
    }

    private final OkHttpClient okHttpClient;
    private final CommodityService commodityService;
    private final IOrderService IOrderService;
    private final IOrderTrackService orderTrackService;

    @Async
    public void getDaRongTracks(String afterCode){
        log.info("开始抓取大荣轨迹数据,afterCode {}", afterCode);
        us.codecraft.webmagic.Request request = new us.codecraft.webmagic.Request("http://www.kerrytj.com/zh/search/table_list.aspx");
        request.setMethod(HttpConstant.Method.POST);
        Map<String,Object> param = new HashMap<>();
        param.put("gno",afterCode);
        request.setRequestBody(HttpRequestBody.form(param,"utf-8"));

        Spider.create(new DarongTrackGetTask(afterCode, IOrderService,orderTrackService))
                .addRequest(request)
                //开启5个线程抓取
                .thread(1)
                //启动爬虫
                .run();
    }
    @Async
    public void getPGSTracks(String afterCode){
        log.info("开始抓取PGS轨迹数据,afterCode {}", afterCode);
        JSONObject param = new JSONObject();
        param.put("number", afterCode);
        RequestBody requestBody = RequestBody.create(JSON,param.toString());
        Request request = new Request.Builder()
                .url(pgsTrackUrl)
                .addHeader("Content-Type","application/json")
                .addHeader("Authorization","eyJhbGciOiJIUzI1NiJ9.eyJwcm92aWRlcl9ub2RlX2lkZW50aXR5IjoiMzhhMzY1N2RjOTBkNmQwMy0yODAzNi0zOTc2ODI5MiIsImN1c3RvbWVyX2lkZW50aXR5IjoiOWI4MDgwZTVlMTBhZmIzOC0yODAzNi0zNjI2Njk4ODU5MzIyNCIsInN0YWZmX2lkZW50aXR5IjpudWxsLCJzdGF0aW9uX2lkZW50aXR5IjpudWxsLCJjb250cmFjdF9pZGVudGl0eSI6bnVsbCwicm9sZSI6ImN1c3RvbWVyIn0.xu4qqJDrnMR9GsWOv_7fg7M2RspjbjAzpL861vOd3cA")
                .post(requestBody)
                .build();
        try (Response response = okHttpClient.newCall(request).execute()) {
            String result = response.body() != null ? response.body().string() : null;
            log.info("开始抓取PGS轨迹返回数据 result {}",result);
            if(result!=null && result.contains("success")){
                processPGSTrack(result,afterCode);
            }
        }catch (Exception e){
            log.error("开始抓取PGS轨迹数据报错 {}",e.getMessage());
        }
    }
    @Async
    public Future<Boolean> pushOrderToDaRong(List<Order> orders) {
        log.info("推送嘉里大荣订单数据开始,orders {}", JSONObject.toJSONString(orders));
        if(orders.size()==0){
            return new AsyncResult<>(true);
        }
        String param = buildOrderPushParam(orders);
        log.info("推送嘉里大荣订单数据入参,param {}", param);
        RequestBody requestBody = RequestBody.create(JSON,param);

        Request request = new Request.Builder()
        .url(pushUrl)
        .post(requestBody)
        .build();
        try (Response response = okHttpClient.newCall(request).execute()){
            String bodyResp = response.body() != null ? response.body().string() : null;
            log.info("推送订单至嘉里大荣返回结果 {}",bodyResp);
            if(!StringUtils.isEmpty(bodyResp)){
                processResult(bodyResp);
            }
        } catch (IOException e) {
            log.error("推送订单至嘉里大荣接口报错 {}",e.getMessage());
            return new AsyncResult<>(false);
        }
        return new AsyncResult<>(true);
    }

    private void processResult(String bodyResp){
        JSONObject result = JSONObject.parseObject(bodyResp);
        String message = result.getString("Message");
        if(!StringUtils.isEmpty(message)){
            log.error("推送订单至嘉里大荣接口Message {}",message);
        }else{
            JSONArray data = result.getJSONArray("Data");
            if(data.size()==0){
                log.error("推送订单至嘉里大荣接口返回Data为空数组");
            }
            List<String> codes = new ArrayList<>();
            List<SsEsId> ssEsIdList = new ArrayList<>();
            data.forEach(obj->{
                JSONObject dataResult = JSONObject.parseObject(obj.toString());
                String afterCode = dataResult.getString("BLN");
                String SSNO = dataResult.getString("SSNO");
                String SSNA = dataResult.getString("SSNA");
                String SSID = dataResult.getString("SSID");
                String ESNO = dataResult.getString("ESNO");
                String ESNA = dataResult.getString("ESNA");
                String ESID = dataResult.getString("ESID");
                SsEsId ssEsId = new SsEsId(SSNO,SSID,SSNA,ESNO,ESID,ESNA,afterCode);
                ssEsIdList.add(ssEsId);
                codes.add(afterCode);
            });
            List<Order> orders = IOrderService.getByAfterCodes(codes);
            orders.forEach(order -> ssEsIdList.forEach(ssEs -> {
                if(order.getAfterCode().equals(ssEs.getAfterCode())){
                    if(!StringUtils.isEmpty(ssEs.getEsid()) && !StringUtils.isEmpty(ssEs.getEsna()) && !StringUtils.isEmpty(ssEs.getEsno())){
                        order.setSsid(ssEs.getSsid());
                        order.setSsna(ssEs.getSsna());
                        order.setSsno(ssEs.getSsno());
                        order.setEsid(ssEs.getEsid());
                        order.setEsna(ssEs.getEsna());
                        order.setEsno(ssEs.getEsno());
                        //设置为推送成功
                        order.setVerifyState(1);
                    }
                    order.setRetryCount(order.getRetryCount() + 1);
                }
            }));
            IOrderService.saveOrUpdateBatch(orders,100);
        }
    }

    private String buildOrderPushParam(List<Order> orders){
        List<String> orderCodes = new ArrayList<>();
        orders.forEach(order -> orderCodes.add(order.getCommodityCode()));

        List<Commodity> commodities = commodityService.getListCommodityBycodes(orderCodes);

        JSONObject param = new JSONObject();
        param.put("ShipDate", LocalDate.now().format(dateTimeFormatter));
        param.put("CustomerNo",customNo);
        param.put("Key",apiKey);
        JSONArray orderArray = new JSONArray();
        orders.forEach(order -> {
            if(StringUtils.isEmpty(order.getAfterCode())){
                log.info("推送订单时订单号为 {} 的订单缺少转单号",order.getCommodityCode());
            }else{
                JSONObject orderParam = new JSONObject();
                int amount = 0;
                List<Commodity> commodityList = commodities.stream().filter(commodity -> commodity.getCommodityCode().equals(order.getCommodityCode())).collect(Collectors.toList());
                for (Commodity commodity : commodityList) {
                    amount += commodity.getAmount();
                }
                orderParam.put("BLN",order.getAfterCode());
                orderParam.put("Consignee",order.getRecipientsName());
                orderParam.put("ConsigneePost",order.getRecipientsPostcode()==null ? "" : order.getRecipientsPostcode());
                orderParam.put("ConsigneeAdd",order.getRecipientsAddress());
                orderParam.put("ConsigneePhone",order.getRecipientsPhone());
                orderParam.put("Weight",order.getWeight());
                orderParam.put("AC","");
                orderParam.put("Piece",amount);
                orderParam.put("Volume","");
                orderParam.put("Remark","");
                orderParam.put("SSNO","");
                orderParam.put("ETP","");
                orderParam.put("CON","");
                orderParam.put("BNO","");
                orderArray.add(orderParam);
            }
        });
        param.put("Data",orderArray);
        return param.toString();
    }

    /**
     * 获取音速轨迹
     * @param afterCode 转运单号
     */
    @Async
    public void getYsTrack(String afterCode){
        log.info("查询音速物流轨迹数据开始,afterCode {}", afterCode);
        Request request = new Request.Builder()
                .url(ysTrackUrl+"expno="+afterCode)
                .build();

        try (Response response = okHttpClient.newCall(request).execute()) {
            String result = response.body() != null ? response.body().string() : null;
            log.info("查询音速物流轨迹返回数据 result {}",result);
            if(result!=null && !result.contains("DOCTYPE")){
                processYsTrack(result,afterCode);
            }
        }catch (Exception e){
            log.error("查询音速物流轨迹数据报错 {}",e.getMessage());
        }
    }

    @Async
    public void getYinsuTrack(String afterCode){
        log.info("抓取音速物流轨迹数据开始,afterCode {}", afterCode);
        us.codecraft.webmagic.Request request = new us.codecraft.webmagic.Request("http://www.ycs-express.com/ExpressQueryM2019.aspx");
        request.setMethod(HttpConstant.Method.POST);
        Map<String,Object> param = new HashMap<>();
        param.put("txtQNo",afterCode);
        param.put("__VIEWSTATEGENERATOR","02F39698");
        param.put("__EVENTVALIDATION","/wEdAAO4gE05fL3BOo4PogFNuzOA/iNAdjrlEo2OzuplGDBxIUUnIjXT2FpiDQq4qdcKsNO9Xx9pbci87AlAXRfHIesA0pYPRuN77Jw1K6E/9XyIIg==");
        param.put("__VIEWSTATE","/wEPDwULLTExMjYxMTg1MDkPZBYCAgMPZBYCAgMPZBYCZg9kFhYCCQ8PFgIeBFRleHRlZGQCDQ8PFgIfAAUMNTE4Nzc4OTYxNzI3ZGQCEQ8PFgIfAAUKMjAxOS8wNS8xMmRkAhUPDxYCHwAFHuWLpOWgg+apn+aisOiCoeS7veaciemZkOWFrOWPuGRkAhcPDxYCHwAFDui1tyDpgYsg5Zyw77yaZGQCGQ8PFgIfAAUG5LiK5rW3ZGQCHQ8PFgIfAGVkZAIhDw8WAh8ABQw1MTg3Nzg5NjE3MjdkZAIjDw8WAh8ABQnkuK3lm5vou4pkZAIlDzwrABEDAA8WBB4LXyFEYXRhQm91bmRnHgtfIUl0ZW1Db3VudAIEZAEQFgAWABYADBQrAAAWAmYPZBYKAgEPZBYGZg8PFgIfAAUQMjAxOS8wNS8xMiAwMDowMGRkAgEPDxYCHwAFD+mfs+mAn+e4veWFrOWPuGRkAgIPDxYCHwAFIlvnmbzku7ZdIOWHuuWPo+S9nOalreS4rSAoMTQ5NzEwMylkZAICD2QWBmYPDxYCHwAFEDIwMTkvMDUvMTMgMTA6MTNkZAIBDw8WAh8ABQYmbmJzcDtkZAICDw8WAh8ABQsyLuW3suWIsOermWRkAgMPZBYGZg8PFgIfAAUQMjAxOS8wNS8xMyAxMDoxOWRkAgEPDxYCHwAFCeWPsOS4reermWRkAgIPDxYCHwAFCzMu6YWN6YCB5LitZGQCBA9kFgZmDw8WAh8ABRAyMDE5LzA1LzEzIDE1OjE1ZGQCAQ8PFgIfAAUJ5Y+w5Lit56uZZGQCAg8PFgIfAAUrNC7lt7LnsL3mlLYg57C95pS26Zec5L+C5Lq6IDog5ZCM5LqLL+imquWPi2RkAgUPDxYCHgdWaXNpYmxlaGRkAicPDxYCHwBlZGQYAQUMR3JpZFZpZXdfUHViDzwrAAwBCAIBZBrgm+R97qsBgL0rlpFZcil8HUXennvnPYCA50IBFMqn");
        request.setRequestBody(HttpRequestBody.form(param,"utf-8"));

        Spider.create(new YinSuTrackGetTask(afterCode, IOrderService,orderTrackService))
                .addRequest(request)
                //开启1个线程抓取
                .thread(1)
                //启动爬虫
                .run();
    }

    private void processYsTrack(String result,String afterCode){
        JSONArray tracks = new JSONArray();
        try{
            tracks = JSONObject.parseArray(result);
        }catch (Exception e){
            log.error("处理音速物流轨迹数据报错 {}",e.getMessage());
        }
        if(tracks.size()>0){
            List<OrderTrack> trackList = new ArrayList<>();
            AtomicBoolean finished = new AtomicBoolean(false);
            tracks.forEach(tracka->{
                JSONObject track = JSONObject.parseObject(tracka.toString());
                String date = track.getString("時間");
                int beginIndex = date.indexOf("(")+1;
                int endIndex = date.lastIndexOf(")");
                String timestamp = date.substring(beginIndex,endIndex);
                long time = Long.valueOf(timestamp);
                String newTime = sdf.format(new Date(time));
                String addr = track.getString("地點");
                String info = track.getString("訊息");
                if(info.contains("已簽收") || info.contains("已完成簽收")){
                    finished.set(true);
                }
                trackList.add(new OrderTrack(newTime,addr,info,afterCode));
            });
            orderTrackService.deleteByAfterCode(afterCode);
            orderTrackService.saveBatch(trackList);
            if(finished.get()){
                IOrderService.updateTrackSuccess(afterCode);
            }
        }
    }

    private void processPGSTrack(String result,String afterCode){
        JSONObject jsonObject =JSONObject.parseObject(result);
        String coreWaybill = jsonObject.getString("core_waybill");
        JSONArray data = JSONObject.parseObject(coreWaybill).getJSONArray("statuses");
        List<OrderTrack> orderTracks = new ArrayList<>();
        if(data.size()>0){
            for(int i =0;i<data.size();i++) {
                Date date = null;
                Date date1 = null;
                String dateStr = null;
                OrderTrack orderTrack = new OrderTrack();
                JSONObject dataResult = JSONObject.parseObject(data.get(i).toString());
                String name = dataResult.getString("name");
                String location = dataResult.getString("location");
                String description =dataResult.getString("description");
                String dates = dataResult.getString("created_at");
                try {
                    dateStr = dates.replace("Z", " UTC");//是空格+UTC
                    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
                    date1 = df.parse(dateStr);
                    SimpleDateFormat df1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
                    date = df1.parse(date1.toString());
                }catch (ParseException e){
                    e.printStackTrace();
                }
                String recorded_at = sdf.format(date);
                orderTrack.setAfterCode(afterCode);
                orderTrack.setScanDate(recorded_at);
                if(org.springframework.util.StringUtils.isEmpty(description)) {
                    orderTrack.setScanInfo(name);
                }else{
                    orderTrack.setScanInfo(name+","+description);
                }
                orderTrack.setScanAddr(location);
                orderTracks.add(orderTrack);
            }
            if(orderTracks.size()>0){
                orderTrackService.deleteByAfterCode(afterCode);
                orderTrackService.saveBatch(orderTracks);
            }
        }
    }

    /**
     * 推送轨迹数据至优速
     * @param afterCode
     */
    @Async
    public void pushTrackToYouSu(String afterCode){
        FormBody formBody = createParam(afterCode);
        if(formBody != null){
//            String resultParam = JSONObject.toJSONString(map);
            log.info("推送嘉里大荣的轨迹至优速 afterCode {},入参 {}",afterCode,formBody.size());
            Request request = new Request.Builder()
                    .url(pushTrackToYouSuUrl)
                    .post(formBody)
                    .build();
            try (Response response = okHttpClient.newCall(request).execute()){
                String bodyResp = response.body() != null ? response.body().string() : null;
                log.info("推送嘉里大荣的轨迹至优速 返回结果 {}",bodyResp);
                if(bodyResp!=null && bodyResp.contains("SUCCESSFUL")){
                    IOrderService.updatePushYousuSuccess(afterCode);
                }
            } catch (IOException e) {
                log.error("推送嘉里大荣的轨迹至优速 报错 {}",e.getMessage());
            }
        }
    }

    private FormBody createParam(String afterCode){
        String paramResult = getTrakData(afterCode);
        if(StringUtils.isEmpty(paramResult)){
            return null;
        }
        try {
            Map<String, String> param = new HashMap<>();
            param.put("partner", account);
            param.put("charset", "GBK");
            param.put("dataType", "json");
            param.put("serviceName", "receive_track");
            param.put("param", paramResult);
            FormBody formBody = new FormBody.Builder()
                .add("partner",account)
                .add("charset","GBK")
                .add("dataType","json")
                .add("urlEncode","true")
                .add("serviceName","receive_track")
                .add("param", urlEncode(paramResult))
                .add("dataSign",SecurityUtil.sign(param, "md5", trackApiKey, "GBK"))
                .build();
            return formBody;
        } catch (Exception e) {
            log.error("生成轨迹发送的数据失败");
        }
        return null;
    }

    private String getTrakData(String afterCode){
        QueryWrapper<OrderTrack> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("after_code",afterCode);
        List<OrderTrack> trackList = orderTrackService.list(queryWrapper);
        if(trackList.size()>0){
            QueryWrapper<Order> orderWrapper = new QueryWrapper<>();
            orderWrapper.eq("after_code",afterCode);
            Order order = IOrderService.getOne(orderWrapper);
            if(order.getCommodityCode().startsWith("3") || order.getCommodityCode().startsWith("5") || order.getCommodityCode().startsWith("9")){
                JSONObject pushObj = new JSONObject();
                JSONObject object = new JSONObject();
                object.put("billCode",order.getCommodityCode());
                JSONArray trackArray = new JSONArray();
                JSONArray tracks = new JSONArray();
                JSONObject obj = new JSONObject();
                trackList.forEach(orderTrack -> {
                    JSONObject track = new JSONObject();
                    track.put("scanTime",orderTrack.getScanDate());
                    track.put("context",orderTrack.getScanInfo());
                    track.put("siteName",orderTrack.getScanAddr());
                    track.put("scanType",0);
                    tracks.add(track);
                });
                obj.put("trace",tracks);
                trackArray.add(obj);
                object.put("traces",trackArray);
                pushObj.put("receivePush",object);
                return pushObj.toString();
            }
        }
        return "";
    }

    private static String urlEncode(String param){
        try {
            return URLEncoder.encode(param,"GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }
}
